﻿using System;
using System.Collections.Generic;
using System.Linq;
using Director.DomainModels;
using Director.StockSharp.Transaq.Native;
using Director.StockSharp.Transaq.Native.Commands;
using Director.StockSharp.Transaq.Native.Responses;
using Veil;

namespace Director
{
	sealed class MyConnector
	{
		public static long FIX_LENGTH = 5000;

		private readonly Action<EServiceState> _stateChangedAction;
		private readonly Action<string> _logAction;
		private readonly Action<string> _errorAction;

		public MyConnector(Action<EServiceState> stateChangedAction, Action<string> logAction, Action<string> errorAction)
		{
			TXmlConnector.DllProxy = new DllProxyReal();
			_stateChangedAction = stateChangedAction;
			_logAction = logAction;
			_errorAction = errorAction;
		}

		public void Connect()
		{
			if (IsConnected)
			{
				return;
			}
			
			_stateChangedAction(EServiceState.Connecting);

			TXmlConnector.ConnectorSetCallback(OnNewStatus, OnNewException);
			
			var credentials = new Credentials("fxziR1kmCbHdm3ITDeEh");

			const string logDirectory = @"D:\HistoryData";

			var cmd = XmlSerializeHelper.Serialize(new ConnectMessage{
				Login =credentials.GetTransaqLogin(),
				Password = credentials.GetTransaqPassword(),
				Address = "89.202.47.152",
				Port = 3900,
				LogsDir = logDirectory,
				Proxy =  Environment.MachineName.StartsWith("PROG8")?new Proxy { Address = "proxy1.local.katharsis.ru", Port = 8080, Login = "FIRST\\chernyshenko", Password = credentials.GetWorkPassword(), Type = ProxyTypes.Http}:null,
			});

			const int statusTimeout = 25;
			TXmlConnector.StatusDisconnected.Reset();
			TXmlConnector.StatusTimeout = statusTimeout*1000;

			if (TXmlConnector.ConnectorInitialize(logDirectory + "\0", 3)) TXmlConnector.StatusDisconnected.Set();
			CheckResponse(TXmlConnector.DllProxy.SendCommand(cmd));
		}

		public bool RequestHistoryData(string boardId, string secCode, int timeFrameId, long? candlesAbsentTillNow=null)
		{
			if (candlesAbsentTillNow == null)
			{
				candlesAbsentTillNow = TXmlConnector.DataHolder.GetCandlesAbsentTillNow(secCode, boardId, timeFrameId);
			}

			if (candlesAbsentTillNow == 0) return true;

			var cmd = XmlSerializeHelper.Serialize(new RequestHistoryDataMessage
			                                       {
				                                       Board = boardId,
				                                       SecCode = secCode,
				                                       Count = candlesAbsentTillNow.Value,
				                                       Period = timeFrameId,
													   Reset = true,
			                                       });

			return CheckResponse(TXmlConnector.DllProxy.SendCommand(cmd));
		}

		public long BuySell(int securityId, int quantity)
		{
			var securirty = TXmlConnector.DataHolder.Securities[securityId];

			var cmd = XmlSerializeHelper.Serialize(new NewOrderMessage()
			{
				//SecId = securityId,
				Board = securirty.Board,
				SecCode = securirty.Code,
				Quantity = Math.Abs(quantity),
				BuySell = quantity>0?BuySells.B : BuySells.S,
				Client = "MCR8413",
				ByMarket = true,
				Unfilled = NewOrderUnfilleds.PutInQueue,
				
			});

			long? transactionId;
			if (CheckResponse(TXmlConnector.DllProxy.SendCommand(cmd), out transactionId))
			{
				return transactionId.GetValueOrDefault();
			}
			return 0;
		}

		public void Subscribe(IEnumerable<Security> securities)
		{
			var c = new SubscribeMessage();
			c.Quotations.AddRange(securities.Select(s => new SecurityId {BoardCode = s.Board, SecurityCode = s.Code}));
			var cmd = XmlSerializeHelper.Serialize(c);
			CheckResponse(TXmlConnector.DllProxy.SendCommand(cmd));
		}

		private bool CheckResponse(string res)
		{
			var response = XmlSerializeHelper.Deserialize(res);
			if (response.IsSuccess) return true;
			if (response.Exception != null)
			{
				_errorAction(response.Exception.Message);
			}
			else
			{
				_logAction(response.Text);	
			}
			return false;
		}

		private bool CheckResponse(string res, out long? transactionId)
		{
			var response = XmlSerializeHelper.Deserialize(res);
			if (response.IsSuccess)
			{
				transactionId = response.TransactionId;
				return true;
			}
			if (response.Exception != null)
			{
				_errorAction(response.Exception.Message);
			}
			else
			{
				_logAction(response.Text);
			}
			transactionId = null;
			return false;
		}

		public bool IsConnected { get; set; }

		private void OnNewStatus(bool newStatus)
		{
			IsConnected = newStatus;
			_stateChangedAction(newStatus ? EServiceState.Connected : EServiceState.Disconnected);
		}

		public void Disconnect()
		{
			if (!IsConnected)
			{
				return;
			}
			TXmlConnector.StatusDisconnected.Reset();
			if (CheckResponse(TXmlConnector.DllProxy.SendCommand("<command id=\"disconnect\"/>")))
			{
				TXmlConnector.ConnectorUnInitialize();
				Log.StopLogging();
				TXmlConnector.DataHolder.Clear();
			}
		}

		private void OnNewException(Exception exception)
		{
			throw new NotImplementedException();
		}


		public void Hello()
		{
			var i = Environment.MachineName=="PROG85"?2:1;
			//TXmlConnector.DllProxy = new DllProxyPlayer("D:\\HistoryData\\Sessions\\" + i + "\\");
		}
	}
}
